package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.cache.GmallCache;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.ProductService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jodd.time.TimeUtil;
import org.apache.commons.lang3.RandomUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Time;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private BaseCategoryViewMapper baseCategoryViewMapper;
    @Autowired
    private SkuInfoMapper skuInfoMapper;
    @Autowired
    private SkuImageMapper skuImageMapper;
    @Autowired
    private SpuSaleAttrMapper spuSaleAttrMapper;
    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SkuAttrValueMapper skuAttrValueMapper;

    //2：查询一二三级分类
    @Override
    public BaseCategoryView getBaseCategoryView(Long category3Id) {

        return baseCategoryViewMapper.selectById(category3Id);
    }



    //查询SkuInfo对象
    @Override
    @GmallCache(prefix = "getSkuInfo")
    public SkuInfo getSkuInfo(Long skuId){
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        //判断是否null
        if (skuInfo != skuInfo){
            List<SkuImage> skuImageList = skuImageMapper.selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
            skuInfo.setSkuImageList(skuImageList);
        }
        return skuInfo;
    }
@Autowired
private RedissonClient redissonClient;
    //1：查询SkuInfo对象

    public SkuInfo getSkuInfo22(Long skuId) {
        //Redisson来解决分布式锁
        //1:查询Redis  K: sku:skuId:info
        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKULOCK_SUFFIX;
        //锁的Key
        String lockKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKULOCK_SUFFIX;
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
        if (skuInfo == null) {
            //参数1： 过期不候  1S
            //参数2： 获取到了锁  让锁什么时候过期
            RLock rLock = redissonClient.getLock(lockKey);
            try {
                boolean lock = rLock.tryLock(1, 1, TimeUnit.SECONDS);
                if (lock) {
                    try {
                        //获取到锁的
                        //3:没有 直接查询DB
                        skuInfo = skuInfoMapper.selectById(skuId);
                        //判断是否为null
                        if (skuInfo != null) {
                            List<SkuImage> skuImageList = skuImageMapper.selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
                            skuInfo.setSkuImageList(skuImageList);
                            //4.保存缓存中一份 100万次-1
                            redisTemplate.opsForValue().set(cacheKey, skuInfo,
                                    RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(500), TimeUnit.SECONDS);

                        }

                    } finally {
                        rLock.unlock();
                    }
                } else {
                    //锁被别人拿走了
                    //查询缓存
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
                return skuInfo;
    }

//    //1：查询SkuInfo对象
//    @Override
//    public SkuInfo getSkuInfo(Long skuId) {
//        //1.查询redis中是否有数据   K: sku:skuId:info
//        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
//        //锁的Key
//        String lockKey = RedisConst.SKUKEY_PREFIX+skuId+RedisConst.SKULOCK_SUFFIX;
//
//        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
//        if (skuInfo == null) {
//            //上锁要求具备原子性操作  setIfAbsent 就是redis中的setnx
//            String uuid = UUID.randomUUID().toString();
//            Boolean isFlag = redisTemplate.opsForValue().setIfAbsent(lockKey, uuid,
//                    1, TimeUnit.SECONDS);
//            if (isFlag){
//                //3.没有数据 直接查询DB
//                skuInfo = skuInfoMapper.selectById(skuId);
//                //判断是否为空
//                if (skuInfo != null){
//                    List<SkuImage> skuImageList = skuImageMapper.
//                            selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
//                    skuInfo.setSkuImageList(skuImageList);
//                    //4.保存缓存中一份  100万次-1。 在原有时间的基础上，加一个随机数，来解决缓存雪崩的问题
//                    redisTemplate.opsForValue().set(cacheKey,skuInfo,
//                            RedisConst.SKUKEY_TIMEOUT+new Random().nextInt(300),
//                            TimeUnit.SECONDS);
//                }else {
//                    //4.保存缓存中一份  空结果也进行缓存，但它的过期时间会很短，最长不超过五分钟。
//                    skuInfo = new SkuInfo();
//                    redisTemplate.opsForValue().set(cacheKey,skuInfo,
//                            5,TimeUnit.MINUTES);
//                }
//                //删除锁 原子性操作
//                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
//                this.redisTemplate.execute(new DefaultRedisScript<>(script),
//                        Collections.singletonList(lockKey), uuid);
//            }else {
//                try {
//                    //查询缓存
//                    TimeUnit.SECONDS.sleep(1);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                return (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
//            }
//        }
//            return skuInfo;
//   }

    //3：查询价格 是不可以优化到缓存中去的
    @Override
    public BigDecimal getPrice(Long skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        //判断是否NULL
        if (skuInfo != null){
            return skuInfo.getPrice();
        }
        return null;
    }

    //4:查询当前商品spu对应的所有的销售属性及属性值集合 并 skuid进行选中
    @Override
    public List<SpuSaleAttr> getSpuSaleAttrAndChecked(Long spuId, Long skuId) {
        return spuSaleAttrMapper.getSpuSaleAttrAndChecked(spuId,skuId);
    }

    //5: 销售属性值ID的组合 对应 skuId 数据
     @Override
     public Map getSaleAttrValuesBySpu(Long spuId) {
         Map result = new HashMap<>();
         List<Map> listMap = skuSaleAttrValueMapper.getSaleAttrValuesBySpu(spuId);
         //将上面ListMap转成Map  性能？  不会   Java  -差-> .class --> runtime
         listMap.forEach(map -> {
             result.put(map.get("value_id"),map.get("sku_id"));
         });
         return result;
    }
    //查询所有分类视图对象集合
    @Override
    public List<BaseCategoryView> getBaseCategoryViewList() {
        return baseCategoryViewMapper.selectList(null);
    }
    //查询平台属性及属性值 根据skuId
    @Override
    public List<SkuSaleAttrValue> getBaseAttrInfoAndBaseAttrValue(Long skuId) {
        return skuAttrValueMapper.getBaseAttrInfoAndBaseAttrValue(skuId);
    }
}
